﻿using Abp.Application.Services.Dto;
using Abp.Auditing;
using Abp.AutoMapper;
using Abp.Collections.Extensions;
using Abp.Domain.Repositories;
using Abp.UI;
using FutureApp.Shop.Dto;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace FutureApp.Shop
{
    /// <AppService/>
    [DisableAuditing]
    public class GoodsAttributeAppService : FutureAppAppServiceBase, IGoodsAttributeAppService
    {
        private IRepository<GoodsAttribute, Guid> GoodsAttributeRepository { get; }
        private IRepository<GoodsAttributeValue, Guid> GoodsAttributeValueRepository { get; }
        private IRepository<GoodsMouldAssemble, Guid> GoodsMouldAssembleRepository { get; }

        /// <constructor/>
        public GoodsAttributeAppService(
            IRepository<GoodsAttribute, Guid> goodsAttributeRepository,
            IRepository<GoodsAttributeValue, Guid> goodsAttributeValueRepository,
            IRepository<GoodsMouldAssemble, Guid> goodsMouldAssembleRepository
        )
        {
            this.GoodsAttributeRepository = goodsAttributeRepository;
            this.GoodsAttributeValueRepository = goodsAttributeValueRepository;
            this.GoodsMouldAssembleRepository = goodsMouldAssembleRepository;
        }

        /// <inheritDoc/>
        public async Task<ListResultDto<GoodsAttributeEntityDto>> GetGoodsAttributeList()
        {
            var list = await this.GoodsAttributeRepository.GetAllListAsync();
            return new ListResultDto<GoodsAttributeEntityDto>(
                list.MapTo<List<GoodsAttributeEntityDto>>()
                );
        }

        /// <inheritDoc/>
        public ListResultDto<GoodsAttributeEntityDto> GetGoodsAttributeList(GetGoodsAttributeListInput input)
        {
            var list = this.GoodsMouldAssembleRepository.GetAll()
                .Where(e => e.MouldId == input.GoodsMould)
                .Select(e => e.Attribute)
                .ToList();
            return new ListResultDto<GoodsAttributeEntityDto>(
                list.MapTo<List<GoodsAttributeEntityDto>>()
                );
        }

        /// <inheritDoc/>
        public async Task<GoodsAttributeEntityDto> GetGoodsAttribute(Guid id)
        {
            if (!await this.ExistGoodsAttribute(id))
                throw new UserFriendlyException(L("NotExistedGoodsAttribute"));
            var entity = await this.GoodsAttributeRepository.GetAsync(id);
            return entity.MapTo<GoodsAttributeEntityDto>();
        }

        /// <inheritDoc/>
        public async Task<GoodsAttributeEntityDto> GetGoodsAttribute(string name)
        {
            if (!await this.ExistGoodsAttribute(name))
                throw new UserFriendlyException(L("NotExistedGoodsAttribute"));
            var entity = await this.GoodsAttributeRepository.FirstOrDefaultAsync(e => e.Name == name);
            return entity.MapTo<GoodsAttributeEntityDto>();
        }

        /// <inheritDoc/>
        public async Task<bool> ExistGoodsAttribute(Guid id)
        {
            var count = await this.GoodsAttributeRepository.CountAsync(e => e.Id == id);
            return count != 0;
        }

        /// <inheritDoc/>
        public async Task<bool> ExistGoodsAttribute(string name)
        {
            var count = await this.GoodsAttributeRepository.CountAsync(e => e.Name == name);
            return count != 0;
        }

        /// <inheritDoc/>
        public async Task CreateGoodsAttribute(CreateGoodsAttributeInput input)
        {
            if (await this.ExistGoodsAttribute(input.Name))
                throw new UserFriendlyException(L("ExistedGoodsAttributeName"));

            var entity = input.MapTo<GoodsAttribute>();
            entity = await this.GoodsAttributeRepository.InsertAsync(entity);
            input.ValueCollection?.Select(val => new GoodsAttributeValue { AttibuteId = entity.Id, Value = val })
                .ToList().ForEach(e => this.GoodsAttributeValueRepository.InsertAsync(e));
        }

        /// <inheritDoc/>
        public async Task DefineGoodsAttributeValue(DefineGoodsAttributeValueInput input)
        {
            if (!await this.ExistGoodsAttribute(input.GoodsAttribute))
                throw new UserFriendlyException(L("NotExistedGoodsAttribute"));
            input.ValueCollection?.Select(val => new GoodsAttributeValue { AttibuteId = input.GoodsAttribute, Value = val })
                .ToList().ForEach(e => this.GoodsAttributeValueRepository.InsertAsync(e));
        }

        /// <inheritDoc/>
        public async Task DeleteGoodsAttribute(Guid id)
        {
            if (!await this.ExistGoodsAttribute(id))
                throw new UserFriendlyException(L("NotExistedGoodsAttribute"));
            if (this.GoodsMouldAssembleRepository.Count(e => e.AttibuteId == id) != 0)
                throw new UserFriendlyException(L("CannotDeleteUsedGoodsAttribute"));
            await this.GoodsAttributeValueRepository.DeleteAsync(e => e.AttibuteId == id);
            await this.GoodsAttributeRepository.DeleteAsync(id);
        }
    }
}
